#!/usr/bin/perl -w

use strict;
use Data::Dumper;
use Getopt::Long;
use IO::Handle;

my $mem_list_long = 100;
my $cpu_list_long = 100;
my $sleep_interval = 10;
my $change_interval = 5;
my $curr_stat_file = '';
my $history_stat_file = '';

our $output_handler;
our $history_handler;

GetOptions("m=i" => \$mem_list_long,
           "c=i" => \$cpu_list_long,
           "s=i" => \$sleep_interval,
           "n=s" => \$change_interval,
           "l=s" => \$curr_stat_file,
           "h=s" => \$history_stat_file);

for (; ;)
{
    $output_handler = \*STDOUT if ($curr_stat_file eq '');
    if ($curr_stat_file ne '')
    {
        open $output_handler, ">", $curr_stat_file;
        $output_handler->autoflush(1);
    }
    if ($history_stat_file ne '')
    {
        open $history_handler, ">>", $history_stat_file;
        $history_handler->autoflush(1);
    }

    for (my $i=0; $i++<$change_interval; sleep($sleep_interval))
    {
        my @proc_mem_report = ();
        my @proc_cpu_report = ();
        my @io_summary = ();
        my @load_summary = ();
        my @mem_summary = ();
        my @cpu_summary = ();

        my %user_profile_info = ();
        my @user_profile = ();

        my @output = `ps aux`;
        shift @output;

        my @proc_info_array = ();
        foreach (@output)
        {
            chomp;
            my @item;
            @item = grep { length($_)>0 } split /\s/;
            my %proc_info = ('user'=>$item[0], 'pid'=>$item[1], 'cpu'=>sprintf("%.2f", $item[2]), 'mem'=>sprintf("%.2f", $item[3]), 'vsz'=>$item[4], 'rss'=>$item[5], 'time'=>$item[9], );
            for (1..(scalar(@item)-10))
            {
                $proc_info{'command'} .= $item[9+$_].' ';
            }
            push(@proc_info_array, \%proc_info);
            $user_profile_info{ $proc_info{'user'} }{'mem'} += $proc_info{'mem'};
            $user_profile_info{ $proc_info{'user'} }{'proc_cnt'} ++;
            $user_profile_info{ $proc_info{'user'} }{'cpu'} += $proc_info{'cpu'};
            $user_profile_info{ $proc_info{'user'} }{'vsz'} += $proc_info{'vsz'};
            $user_profile_info{ $proc_info{'user'} }{'rss'} += $proc_info{'rss'};
        }

        @proc_mem_report = sort { $b->{'mem'} <=> $a->{'mem'} } @proc_info_array;
        @proc_cpu_report = sort { $b->{'cpu'} <=> $a->{'cpu'} } @proc_info_array;
        @user_profile = sort { $user_profile_info{$b}->{'vsz'} <=> $user_profile_info{$a}->{'vsz'} } keys %user_profile_info;

        print $output_handler `uptime`, "\n";
        print $output_handler `vmstat`, "\n";
        print $history_handler `uptime`, "\n" if (defined($history_handler));
        print $history_handler `vmstat`, "\n" if (defined($history_handler));
        my $output_proc_mem_report = output_proc_report('process mem report', \@proc_mem_report, $mem_list_long);
        my $output_proc_cpu_report = output_proc_report('process cpu report', \@proc_cpu_report, $cpu_list_long);
        output_user_report(\@user_profile, \%user_profile_info);
        &$output_proc_mem_report();
        &$output_proc_cpu_report();

        print $output_handler "..............................#.....................................#...............................\n";
        print $output_handler "..........################################################################################..........\n";
        print $output_handler "..............................#.....................................#...............................\n";
    }
    close($output_handler) if ($curr_stat_file ne '');
    close($history_handler) if (defined($history_handler));
}

sub output_proc_report
{
    my $title = shift;
    my $info_array = shift;
    my $total = shift;
    
    return sub
    {
        my $cnt = 0;
        print $output_handler "----------\t", uc($title), "\t----------\n";
        print $output_handler "USER\tPID\tCPU\tMEM\tTIME\tRSS\tVSZ\tCMD\n";
        print $history_handler "----------\t", uc($title), "\t----------\n" if (defined($history_handler));
        print $history_handler "USER\tPID\tCPU\tMEM\tTIME\tRSS\tVSZ\tCMD\n" if (defined($history_handler));
        foreach (@$info_array)
        {
            last if ($cnt++ >= $total);
            print $output_handler $_->{'user'}, "\t", $_->{'pid'}, "\t", $_->{'cpu'}, "\t", $_->{'mem'}, "%\t", $_->{'time'}, "\t", $_->{'rss'}, "\t", $_->{'vsz'}, "\t", $_->{'command'}, "\n";
            print $history_handler $_->{'user'}, "\t", $_->{'pid'}, "\t", $_->{'cpu'}, "\t", $_->{'mem'}, "%\t", $_->{'time'}, "\t", $_->{'rss'}, "\t", $_->{'vsz'}, "\t", $_->{'command'}, "\n" if (defined($history_handler));
        }
        print $output_handler "\n";
        print $history_handler "\n" if (defined($history_handler));
    }
}

sub output_user_report
{
    my $user_list = shift;
    my $info_ref = shift;
    print $output_handler "----------\t", uc('user profile report'), "\t----------\n";
    print $output_handler "USER\tPROC\tCPU\tMEM\tRSS\tVSZ\n";
    print $history_handler "----------\t", uc('user profile report'), "\t----------\n" if (defined($history_handler));
    print $history_handler "USER\tPROC\tCPU\tMEM\tRSS\tVSZ\n" if (defined($history_handler));
    foreach (@$user_list)
    {
        print $output_handler $_, "\t", $info_ref->{$_}{'proc_cnt'}, "\t", $info_ref->{$_}{'cpu'}, "\t", $info_ref->{$_}{'mem'}, "%\t", $info_ref->{$_}{'rss'}, "\t", $info_ref->{$_}{'vsz'}, "\n";
        print $history_handler $_, "\t", $info_ref->{$_}{'proc_cnt'}, "\t", $info_ref->{$_}{'cpu'}, "\t", $info_ref->{$_}{'mem'}, "%\t", $info_ref->{$_}{'rss'}, "\t", $info_ref->{$_}{'vsz'}, "\n" if (defined($history_handler));
    }
    print $output_handler "\n";
    print $history_handler "\n" if (defined($history_handler));
}
